package com.wsoft.websocket.config;

import com.wsoft.core.service.CommonAccountService;
import com.wsoft.core.vo.AccountVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @Author Zhang gukai
 * @Date 2025/1/9 9:21
 */
public class WebSocketHandler extends TextWebSocketHandler {

    @Autowired
    private CommonAccountService commonAccountService;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 存储用户id和其对应的session  --> ConcurrentHashMap
     */
    private static final HashMap<String, WebSocketSession> USERS = new HashMap<>();

    private static final HashMap<String, WebSocketSession> USER_WEB = new HashMap<>();

    private static final HashMap<String, WebSocketSession> USER_APP = new HashMap<>();

    private static final HashMap<String, WebSocketSession> USER_XCX = new HashMap<>();


    /**
     * 定时任务线程池，用于发送心跳
     */
    private final ScheduledExecutorService heartbeatScheduler = Executors.newScheduledThreadPool(1);

    /**
     * 心跳间隔时间（单位：秒）
     */
    private static final long HEARTBEAT_INTERVAL = 30;

    /**
     * 连接建立后触发
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        // 取出在拦截器中存储的username
        String client = session.getAttributes().get("WEBSOCKET_CLIENT").toString();
        String userId =session.getAttributes().get("WEBSOCKET_USERID").toString();
        logger.info(userId+":"+client +"成功建立websocket连接!");
        USERS.put(userId+":"+client, session);
        switch (session.getAttributes().get("WEBSOCKET_CLIENT").toString()){
            case "web":
                USER_WEB.put(userId, session);
                break;
            case "app":
                USER_APP.put(userId, session);
                break;
            case "xcx":
                USER_XCX.put(userId, session);
                break;
            default:
        }
        AccountVO accountVO = new AccountVO();
        accountVO.setIsOnline(0);
        accountVO.setMemberId(Long.parseLong(userId));
        commonAccountService.updateOnline(accountVO);
        logger.info("当前线上用户数量:{}",USERS.size());

        // 启动心跳任务
        startHeartbeat(session);
    }

    /**
     * 关闭连接时触发
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
        String client = session.getAttributes().get("WEBSOCKET_CLIENT").toString();
        String userId = session.getAttributes().get("WEBSOCKET_USERID").toString();
        logger.info("用户{}:已退出！", userId+":"+client);
        USERS.remove(userId + ":" + client, session);
        switch (session.getAttributes().get("WEBSOCKET_CLIENT").toString()) {
            case "web":
                USER_WEB.remove(userId, session);
                break;
            case "app":
                USER_APP.remove(userId, session);
                break;
            case "xcx":
                USER_XCX.remove(userId, session);
                break;
            default:
        }
        AccountVO accountVO = new AccountVO();
        accountVO.setIsOnline(1);
        accountVO.setMemberId(Long.parseLong(userId));
        commonAccountService.updateOnline(accountVO);
        logger.info("剩余在线用户{}", USERS.size());
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("Received message: " + message.getPayload() + " from session: " + session.getId());
            try {
                if (session.isOpen()) {
                    session.sendMessage(new TextMessage("Echo: " + message.getPayload()));
                    //todo 往mq队列里发送消息
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
    if (session.isOpen()) {
        session.close();
    }
    logger.error("传输出现异常，关闭websocket连接... ");
    String client = session.getAttributes().get("WEBSOCKET_CLIENT").toString();
    String userId = session.getAttributes().get("WEBSOCKET_USERID").toString();
    logger.info("用户{}:已退出！", userId + ":" + client);
    USERS.remove(userId + ":" + client, session);
    switch (session.getAttributes().get("WEBSOCKET_CLIENT").toString()) {
        case "web":
            USER_WEB.remove(userId, session);
            break;
        case "app":
            USER_APP.remove(userId, session);
            break;
        case "xcx":
            USER_XCX.remove(userId, session);
            break;
        default:
    }
            AccountVO accountVO = new AccountVO();
            accountVO.setIsOnline(1);
            accountVO.setMemberId(Long.parseLong(userId));
            commonAccountService.updateOnline(accountVO);

}
    /**
     * 给某个用户发送消息
     */

    public void sendMessageToUser(String userId, TextMessage message) {
        for (String id : USERS.keySet()) {
            if (id.equals(userId)) {
                try {
                    if (USERS.get(id).isOpen()) {
                        USERS.get(id).sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

    /**
     * 小程序端
     * @param userId
     * @param message
     */
    public void sendMessageToXcx(String userId, TextMessage message) {
        for (String id : USER_XCX.keySet()) {
            if (id.equals(userId)) {
                try {
                    if (USER_XCX.get(id).isOpen()) {
                        USER_XCX.get(id).sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

    /**
     * app端
     * @param userId
     * @param message
     */
    public void sendMessageToApp(String userId, TextMessage message) {
        for (String id : USER_APP.keySet()) {
            if (id.equals(userId)) {
                try {
                    if (USER_APP.get(id).isOpen()) {
                        USER_APP.get(id).sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

    /**
     * web端
     * @param userId
     * @param message
     */
    public void sendMessageToWeb(String userId, TextMessage message) {
        for (String id : USER_WEB.keySet()) {
            if (id.equals(userId)) {
                try {
                    if (USER_WEB.get(id).isOpen()) {
                        USER_WEB.get(id).sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
    /**
     * 启动心跳任务
     */
    private void startHeartbeat(WebSocketSession session) {
        heartbeatScheduler.scheduleAtFixedRate(() -> {
            try {
                if (session.isOpen()) {
                    String heartbeatMessage = "{\"type\":\"heartbeat\"}";
                    session.sendMessage(new TextMessage(heartbeatMessage));
                    logger.info("向用户 {} 发送心跳消息", session.getAttributes().get("WEBSOCKET_USERID"));
                }
            } catch (IOException e) {
                logger.error("发送心跳消息失败: {}", e.getMessage());
            }
        }, HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);
    }

    /**
     * 停止心跳任务
     */
    private void stopHeartbeat(WebSocketSession session) {
        // 这里可以根据需要实现停止逻辑
        // 由于 ScheduledExecutorService 是针对全局的，无法直接停止单个任务
        // 可以通过在任务中检查 session 是否关闭来实现
    }

    }